Summary ¶
Set your messages in a controller:
Yii::app()->user->setFlash('success', "Data1 saved!");
Yii::app()->user->setFlash('error', "Data2 failed!");
Yii::app()->user->setFlash('notice', "Data3 ignored.");
Display them in your view:
<?php
foreach(Yii::app()->user->getFlashes() as $key => $message) {
echo '<div class="flash-' . $key . '">' . $message . "</div>\n";
}
?>
Setting flash messages ¶
A flash message is used in order to keep a message in session through one or several requests of the same user. By default, it is removed from session after it has been displayed to the user. Flash messages are usually used in combination with HTTP redirections, because in this case there is no view, so messages can only be displayed in the request that follows redirection.
A flash message has a name and a content (AKA key and value). It is an entry of an associative array. The name is a string: often "notice", "success", or "error", but it can be anything. The content is usually a string. You can put HTML tags in your message if you display it raw. You can also set the message value to a number or an array: it will be serialized and kept in session like a string.
Flash messages can be set using the setFlash() Method of [CWebUser]. For example, if you would like to inform the user that his changes were successfully saved, you could add the following line to your Controller:
<?php
Yii::app()->user->setFlash('success', "Data saved!");
$this->redirect(array('thing/view', 'id' => 1));
In this example we used the key 'success'. If you want to define more than one flash messages, you will have to use different keys.
Displaying flash messages ¶
To check for flash messages we use the hasFlash() Method and to obtain the flash message we use the getFlash() Method. Since Yii v1.1.3, there is also a method getFlashes() to fetch all the messages.
By default, fetching a message deletes it from the session. This means that a message is meant to be displayed only on the first page served to the user. The fetching methods have a boolean parameter that can change this behavior. See the API links in the previous paragraph.
Displaying statically ¶
So showing of the flash message defined above in a view is done by
<?php if(Yii::app()->user->hasFlash('success')):?>
<div class="info">
<?php echo Yii::app()->user->getFlash('success'); ?>
</div>
<?php endif; ?>
These few lines of code will make a flash message with the key "success" visible to the user within a div of class "info". The message will be displayed until this or another page is (re)loaded in the browser.
If you want to always display all the flash messages, then you should add a block to your layout (by default protected/views/layout/main.php
). Here is a more elaborate example:
<?php
$flashMessages = Yii::app()->user->getFlashes();
if ($flashMessages) {
echo '<ul class="flashes">';
foreach($flashMessages as $key => $message) {
echo '<li><div class="flash-' . $key . '">' . $message . "</div></li>\n";
}
echo '</ul>';
}
?>
The default CSS created by the Yii script yiic webapp
has directives for three classes of flash messages on a div tag: flash-error
, flash-notice
, flash-success
.
The best way to know if some flash messages are set is to check if Yii::app()->user->getFlashes()
is empty. Since v1.1.7, Yii keeps an associative array of the flash keys in the form array("key1" => 0, ...)
, or null
if not flash message is set. You can fetch this with Yii::app()->user->getState(CWebUser::FLASH_COUNTERS)
but this is not recommended, as Yii could change this internal process.
Displaying dynamically (with Javascript) ¶
If you want the flash message to appear somewhere above the content and then automatically fade out after a few seconds, you will have to add the following lines to your view:
<?php
Yii::app()->clientScript->registerScript(
'myHideEffect',
'$(".info").animate({opacity: 1.0}, 3000).fadeOut("slow");',
CClientScript::POS_READY
);
?>
With these lines of code we register a piece of jQuery (already included with YII) javascript code, using 'myHideEffect' as ID. It will be inserted in the jQuery's ready function (CClientScript::POS_READY). Due to the chainablity of jQuery the little script will run two effects on the .info DIV sequentially:
[javascript]
.animate({opacity: 1.0}, 3000)
Normally this would animate the .info DIV to a full opacity within 3 seconds. But the DIV is already rendered with full opacity upon page load, so calling this effect will just cause a delay for 3 seconds.
[javascript]
.fadeOut("slow")
This is the fadeOut effect which will hide the .info DIV at slow speed.
Further readings (JS): ¶
- More information about the jQuery effects can be found here.
- Using CJuiDialog to display flash Messages in Dialogues
Links ¶
- CWebUser API
- A more specific use of flash messages: An easy way to display a success page using flash messages
Works great!
I tried the following code in my view file. Works Great!
<?php Yii::app()->clientScript->registerScript( 'myHideEffect', '$(".flash-success").animate({opacity: 1.0}, 3000).fadeOut("slow");', CClientScript::POS_READY ); ?> <?php if(Yii::app()->user->hasFlash('success')):?> <div class="flash-success"> <?php echo Yii::app()->user->getFlash('success'); ?> </div> <?php endif; ?>
JavaScript delays
This will not work.
~~~
setTimeout(3000, function(){ $(".info").fadeOut("slow"); });
~~~
This one does.
~~~
setTimeout(function(){ $(".info").fadeOut("slow"); },3000);
~~~
Automated display of flash messages
The main.css file from the default set of CSS files coming with Yii defines these three classes: div.flash-error, div.flash-notice and div.flash-success. You can use them to automate display of flash messages to the user in accordance with their type ("error", "notice" or "success"). Here is how.
Step 1. Put this method into your WebUser class:
/** * @return array flash message keys array */ public function getFlashKeys() { $counters=$this->getState(self::FLASH_COUNTERS); if(!is_array($counters)) return array(); return array_keys($counters); }
Step 2. Put this piece of code into your layout or view where a flash message would be appropriate:
<?php $user=Yii::app()->getUser(); foreach($user->getFlashKeys() as $key): if($user->hasFlash($key)): ?> <div class="flash-<?php echo $key; ?>"> <?php echo $user->getFlash($key); ?> </div> <?php endif; endforeach; ?>
Step 3. Put lines of code similar to these where appropriate to notify the user of the corresponding event types:
Yii::app()->getUser()->setFlash('error','Could not save data to the database.'); Yii::app()->getUser()->setFlash('notice','There was nothing to save.'); Yii::app()->getUser()->setFlash('success','The data was successfully saved to the database.');
Javascript Delays
`$(".info").animate({opacity: 1.0}, 3000).fadeOut("slow");`
The animate call on this line of code is used as a hack to perform a delay. As specified shortly after it was written. However, the one problem with using this method is that it consumes CPU resources for no real purpose. You can use this instead:
~~~
setTimeout(3000, function(){ $(".info").fadeOut("slow"); });
~~~
This method will not consume resources for the delay.
On another note, however. If you want to display information to a user, it is usually recommended that you leave the information on the screen until the user supplies input to say they want it to go away. There is nothing more annoying than having an error message fadeOut before you have time to read the whole thing.
You can do this by put a close image/button/link somewhere in the message area that the user can click and use the following line (assuming the id of your link is 'close_btn':
~~~
$('#close_btn').click(function(){ $(".info").fadeOut("slow"); });
~~~
Update to post by 'sova'
Since v1.1.3 the CWebUser::getFlashes method is available, which makes automatic display of flash messages even easier:
<?php foreach(Yii::app()->user->getFlashes() as $key => $message) { if ($key=='counters') {continue;} echo "<div class='flash-{$key}'>{$message}</div>"; } ?>
Not work with Ajax Validation
On CActiveForm widget, which usually generated by Gii, when the form is submit, there are 2 request, one for sending the data normally from the Submit button, and one for perform Ajax validation.
Strange that the ajax validation request is performed after the normal one. So there is no way to save the Flash session data for 3rd request (the redirect page).
I have to disable ajax validation to make it work.
Since 1.1.3 we can use...
<?php foreach(Yii::app()->user->getFlashes() as $key => $message) { if ($key=='counters') {continue;} //no need next line since 1.1.7 echo "<div class='flash-{$key}'>{$message}</div>"; } ?>
Javascript Delays
jquery delay method
[javascript] $(".info").delay(3000).fadeOut("slow");
autoUpdateFlash
This thing has caused me headache, hope can help others too..
Yii's flash message only persist on first and second request. On the third request it will disappear. To prevent this behavior we must set the CWebUser's autoUpdateFlash to false. That way, the flash message will only deleted after calling getFlash()
'user'=>array( ... 'autoUpdateFlash' => false, // add this line to disable the flash counter ),
Reference : http://www.yiiframework.com/forum/index.php?/topic/21077-flash-messages-and-redirect/
POST_END
When using POST_READY on certain situations, you may notice a initial undesired blink. You can try to fix it, by using CSS and display:none; however, when you have several flash messages to display instead of just one, you have to play with foreach flags and so forth...
I found out that, on certain situations, if instead of POST_READY I use POST_END, no more blinking undesired effect appears.
Hope it saves some time to someone.
Flash Message and Redirect
Hi there!
I still have this problem. Using Yii 1.1.14, I have set the option [code]autoUpdateFlash[/code] to [code]false[/code], but still no flash message after a redirect.
Thanks for the help.
Cheers!
Multiple Flash Messages
I found it possible to pass multiple flash messages via passing an array.
if ($model->load(Yii::$app->request->post())) { // get the uploaded file instance. for multiple file uploads // the following data will return an array $images = UploadedFile::getInstances($model, 'image'); $errors = Array(); foreach($images as $image) { //Save Image //Save Model try{ $model->save(); } catch(db\IntegrityException $e) { $errors[] = $model->name; } } Yii::$app->session->setFlash('error', $errors); return $this->redirect(['index']); }
Using this method you could store multiple flashes for each type, success, error et cetera
I displayed like this (am using kartik\widgets\Alert for prettier errors)
<? $errors = Yii::$app->session->getFlash('error') ?> <? if(isset($errors)) { $base_delay = 0; foreach($errors as $error) { $base_delay += 1500; echo Alert::widget([ 'type' => Alert::TYPE_DANGER, 'title' => 'Error Logo Exists!', 'icon' => 'glyphicon glyphicon-exclamation-sign', 'body' => $error, 'showSeparator' => true, 'delay' => $base_delay, ]); } } ?>
This works really well for me and solves a problem I have had for ages lol.
how to use it when use Ajax button, I need to display flash message after ajax request returned
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.